import { Component, OnInit, ElementRef, Renderer2, Input, OnDestroy, OnChanges, EventEmitter, AfterViewInit, ViewChild, Output, SimpleChanges } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { WindowWrapper } from '../shared/services';


@Component({
  selector: 'el-select',
  templateUrl: './select.component.html',
  providers: [{
    provide: NG_VALUE_ACCESSOR,
    useExisting: SelectComponent,
    multi: true
  }],
})
export class SelectComponent implements OnInit, OnDestroy, OnChanges, AfterViewInit, ControlValueAccessor {
  private el: any;
  private renderer: any;
  private window: any;
  private controlChange: any = function () { };
  private controlTouch: any = function () { };
  @ViewChild('tags') tags: any;
  @ViewChild('input') input: any;
  @Input() disabled: boolean = false;
  @Input() clearable: boolean = false;
  @Input() name: string = '';
  @Input() size: string = '';
  @Input() placeholder: string = '请选择';
  @Input() multiple: boolean = false;
  @Input('popper-class') popperClass: string = '';
  @Input('multiple-limit') multipleLimit: Number = 0;
  @Input() model: any;
  @Output('change') modelChange: EventEmitter<any> = new EventEmitter();
  @Input() selfWidth: string = '';
  @Input() subscriber: any = [];
  @Input() multipleLabels: Array<string | number> = [];
  @Input() multiplePlaceholder: string = this.placeholder;
  @Input() dropdownActive: boolean = false;
  @Input() selectedLabel: string | number = '';
  @Input() iconClass: string = 'el-icon-arrow-up';
  @Input() globalListener: any;
  readonly:boolean=true;
  private selectOptions: any=[];
  constructor(el: ElementRef, renderer: Renderer2, window: WindowWrapper) {
    this.el = el;
    this.renderer = renderer;
    this.window = window;
  }
  ngOnDestroy(): void {
    this.globalListener && this.globalListener();
  }
  ngOnChanges(changes: SimpleChanges): void {
    // not include model
    if (!changes || !changes.model)
      return;
    if (changes.model.isFirstChange())
      return;
    // reset model
    if (!changes.model.currentValue) {
      this.selectedLabel = changes.model.currentValue;
      this.model = changes.model.currentValue;
      this.modelChange.emit(changes.model.currentValue);
      this.controlChange(this.model);
    }
    this.subscriber.forEach(function (sub: any) { return sub(); });
  }
  ngAfterViewInit(): void {
    var _this = this;
    var /** @type {?} */ timer = this.window.setTimeout(function () {
      _this.initModelWithMultipleMode();
      _this.window.clearTimeout(timer);
    }, 0);
  }
  writeValue(value: any): void {
    this.model = value;
    this.initModelWithMultipleMode();
  }
  registerOnChange(fn: any): void {
    this.controlChange = fn;
  }
  registerOnTouched(fn: any): void {
    this.controlTouch = fn;
  }


  ngOnInit(): void {
    var _this = this;
    var /** @type {?} */ timer = window.setTimeout(function () {
      _this.selfWidth = _this.el.nativeElement.getBoundingClientRect().width;
      clearTimeout(timer);
    }, 0);
    this.globalListener = this.renderer.listen('document', 'click', function () {
      _this.dropdownActive && _this.toggleHandle(null);
    });
    this.updatePlaceholderWithMultipleMode();
  }

  mouseHandle(isEnter: any) {
    
    if (isEnter === void 0) { isEnter = false; }
    this.clearable = this.clearable && !this.multiple;
    if (!this.clearable || !this.model)
      return;
    this.iconClass = "" + (isEnter ? 'el-icon-circle-close is-reverse' : 'el-icon-arrow-up');
  }

  toggleHandle(event: any) {
    this.clearable = this.clearable && !this.multiple;
    if (this.disabled)
      return;
    event && event.stopPropagation();
    this.dropdownActive = !this.dropdownActive;
    var /** @type {?} */ nextClass = 'el-icon-arrow-up' + (this.dropdownActive ? ' is-reverse' : '');
    this.iconClass = !this.isClearable() ? nextClass : this.iconClass;
  }


  clearSelected(event: any) {
    event.stopPropagation();
    this.clearable = this.clearable && !this.multiple;
    if (!this.clearable)
      return;
   
    // reset icon
    this.mouseHandle(false);
    // reset selected label
    this.changeLabel(null, null);
    // reset model
    this.model = null;
    this.modelChange.emit(this.model);
    this.controlChange(this.model);
    this.subscriber.forEach(function (sub: any) { return sub(); });
    // close dropdown menu
    this.dropdownActive = false;
    
  }


  changeLabel(nextLabel: any, nextValue: any) {
    event && event.stopPropagation();
    if(!this.multiple) {
      this.dropdownActive && this.toggleHandle(null);
    }
    
    // only update label
    this.selectedLabel = this.multiple ? '' : nextLabel;
    if (!nextValue || this.model === nextValue)
      return;
    if (this.multiple) {
      if(this.multipleLimit <= 0 || this.model.length < this.multipleLimit) {
        this.updateValueWithMultipleMode(nextLabel, nextValue);
        this.updateLayoutWithMultipleMode();
      }
      
    }
    else {
      this.model = nextValue;
    }
    this.modelChange.emit(this.model);
    this.controlChange(this.model);
    this.subscriber.forEach(function (sub:any) { return sub(); });
  }

  isClearable(){
    return (this.clearable && this.model) ? true : false;
  }

  appendOptions(item: any) {
    this.selectOptions.push(item);
  }


  updateLayoutWithMultipleMode() {
    var _this = this;
    var /** @type {?} */ updateHandle = function () {
      if (!_this.tags)
        return;
      var /** @type {?} */ children = _this.tags.nativeElement && _this.tags.nativeElement.children;
      var /** @type {?} */ inputEl = _this.input.el.nativeElement;
      if (!children || !children.length || !inputEl)
        return;
      var /** @type {?} */ inputWidth = inputEl.getBoundingClientRect().width;
      var /** @type {?} */ unit = inputWidth - 34;
      var /** @type {?} */ row = 1;
      Array.from(children).reduce(function (count:any, el:any) {
        var /** @type {?} */ currentWidth = el.getBoundingClientRect().width || 80;
        if (count + currentWidth < unit)
          return count + currentWidth;
        // add a row
        row++;
        return currentWidth;
      }, 0);
      var /** @type {?} */ el = inputEl.querySelector('.el-input__inner');
      _this.renderer.setStyle(el, 'height', Math.ceil(row) * 40 + "px");
    };
    var /** @type {?} */ timer = this.window.setTimeout(function () {
      updateHandle();
      _this.window.clearTimeout(timer);
    }, 0);
  }


  updateValueWithMultipleMode(nextLabel: any, nextValue: any) {
    var /** @type {?} */ model = Array.isArray(this.model)
      ? (this.model.indexOf(nextValue) > -1 ? this.model.filter(function (v) { return v !== nextValue; }) : this.model.concat(nextValue))
      : [nextValue];
    this.model = model.filter(function (r) { return r !== undefined; });
    this.multipleLabels = !nextLabel || this.multipleLabels.indexOf(nextLabel) > -1
      ? this.multipleLabels.filter(function (v) { return v !== nextLabel; })
      : this.multipleLabels.concat(nextLabel);
    this.updatePlaceholderWithMultipleMode();
  }

  updatePlaceholderWithMultipleMode() {
    if (!this.multiple)
      return;
    this.multiplePlaceholder = this.model && this.model.length ? '' : this.placeholder;
  }

  initModelWithMultipleMode() {
    var _this = this;
    if (!this.model || !this.multiple || !this.selectOptions.length)
      return;
    if (!Array.isArray(this.model))
      this.model = [this.model];
    this.multipleLabels = this.model
      .map(function (item:any) {
        var /** @type {?} */ option = _this.selectOptions.find(function (option:any) { return option.value === item; });
        if (option && option.label)
          return option.label;
        return null;
      })
      .filter(function (r:any) { return !!r; });
    this.updateLayoutWithMultipleMode();
  }
}
